package interactiond

import (
	"time"

	"github.com/globalsign/mgo"
	"github.com/globalsign/mgo/bson"
	"github.com/pkg/errors"
	cinteractiond "gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/interactiond"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/core/repo/mgorepo/baser"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/ddd"
	"gogs.xiaoyuanjijiehao.com/antlinker/antcms/log"
)

type groupRepo struct {
	baser.BaseRepo
}

func (r groupRepo) CreGroup(ctx ddd.Context, id string, desc cinteractiond.GroupDesc, e cinteractiond.GroupCtrl) (err error) {
	now := time.Now()
	c := collGroup{}
	c.FullDesc(desc)
	c.FullCtrl(e)
	c.CreTime = now
	c.GroupID = id
	c.Status = cinteractiond.IGStatusNormal
	return r.DBInsert(ctx, c)
}

func (r groupRepo) GetGroup(ctx ddd.Context, id string) (*cinteractiond.GroupAggregate, error) {
	a, err := r.GetByCollAggregate(ctx, &collGroup{GroupID: id})
	if err != nil || a == nil {
		if err == mgo.ErrNotFound {
			return nil, nil
		}
		return nil, err
	}
	return a.(*cinteractiond.GroupAggregate), nil
}
func (r groupRepo) QueryByIDS(ctx ddd.Context, igids []string) (result []cinteractiond.GroupAggregate, err error) {
	query := bson.M{
		"_id": bson.M{"$in": igids},
	}
	var cs []collGroup
	err = r.DBQuery(ctx, collNameGroup, query, nil, nil, &cs)
	if len(cs) == 0 || err != nil {
		if err == mgo.ErrNotFound {
			err = nil
		}
		return
	}
	for _, c := range cs {
		a := c.ToGroupAggregate()
		a.Init(a, r.AggregateRoot(), a.IGID)
		result = append(result, *a)
	}
	return
}
func (r groupRepo) AddReplayNum(ctx ddd.Context, igid string, t cinteractiond.ChildReplyTotal) (err error) {
	update := bson.M{
		"$inc": bson.M{"replayNum": t.ReplayNum},
		"$set": bson.M{"lastTime": t.LastTime, "lastReplayer": t.LastReplayer},
	}
	return r.DBUpdate(ctx, collNameGroup, bson.M{"_id": igid}, update, true)
}
func (r groupRepo) AddIntsNum(ctx ddd.Context, igid string, code string, value int) (err error) {
	for {
		// 实现乐观锁　igid　必须存在　调用该方法前已经校验
		g, err := r.GetGroup(ctx, igid)
		if err != nil {
			return err
		}
		avg := 0.0
		for _, t := range g.GroupTotal {
			if t.ITCode == code {
				avg = float64(t.TotalScore+value) / float64(t.Total+1)
				break
			}
		}

		query := bson.M{
			"_id":           igid,
			"totals.itCode": code,
		}
		update := bson.M{
			"$inc": bson.M{
				"totals.$.total":      1,
				"totals.$.totalScore": value,
			},
			"$set": bson.M{"totals.$.avgScore": avg},
		}
		// 修改统计信息
		if err := r.DBUpdate(ctx, collNameGroup, query, update, true); err != mgo.ErrNotFound {
			if err != nil {
				return errors.Wrapf(err, "更新互动组互动统计失败．")
			}
			return nil
		}
		//　找不到　　"totals.itCode"　新增
		log.Debug("触发乐观锁 新增")
		query = bson.M{
			"_id":    igid,
			"totals": bson.M{"$not": bson.M{"$elemMatch": bson.M{"itCode": code}}},
		}
		update = bson.M{
			"$addToSet": bson.M{"totals": bson.M{"itCode": code, "total": 1, "totalScore": value, "avgScore": value}},
		}
		if err := r.DBUpdate(ctx, collNameGroup, query, update, true); err != mgo.ErrNotFound {
			if err != nil {
				return errors.Wrapf(err, "新增互动组互动统计失败．")
			}
			return nil
		}
		log.Debug("触发乐观锁　下一次更新")
		// 新增时出现 mgo.ErrNotFound 已经新增重新回到开始进行更新
	}
}

func (r groupRepo) SubIntsNum(ctx ddd.Context, igid string, code string, value int) (err error) {
	for {
		// 实现乐观锁　igid　必须存在　调用该方法前已经校验
		g, err := r.GetGroup(ctx, igid)
		if err != nil {
			return err
		}
		avg := 0.0
		for _, t := range g.GroupTotal {
			if t.ITCode == code {
				avg = float64(t.TotalScore-value) / float64(t.Total-1)
				break
			}
		}

		query := bson.M{
			"_id":           igid,
			"totals.itCode": code,
		}
		update := bson.M{
			"$inc": bson.M{
				"totals.$.total":      -1,
				"totals.$.totalScore": -value,
			},
			"$set": bson.M{"totals.$.avgScore": avg},
		}
		// 修改统计信息
		if err := r.DBUpdate(ctx, collNameGroup, query, update, true); err != mgo.ErrNotFound {
			if err != nil {
				return errors.Wrapf(err, "删除互动组互动统计失败．")
			}
			return nil
		}
		//　找不到　　"totals.itCode"　新增
		log.Debug("触发乐观锁 新增")
		query = bson.M{
			"_id":    igid,
			"totals": bson.M{"$not": bson.M{"$elemMatch": bson.M{"itCode": code}}},
		}
		update = bson.M{
			"$addToSet": bson.M{"totals": bson.M{"itCode": code, "total": 0, "totalScore": 0, "avgScore": 0}},
		}
		if err := r.DBUpdate(ctx, collNameGroup, query, update, true); err != mgo.ErrNotFound {
			if err != nil {
				return errors.Wrapf(err, "删除互动组互动统计失败．")
			}
			return nil
		}
		log.Debug("触发乐观锁　下一次更新")
		// 新增时出现 mgo.ErrNotFound 已经新增重新回到开始进行更新
	}
}

func (r groupRepo) UpdateIntsNum(ctx ddd.Context, igid string, code string, old int, new int) (err error) {
	c := new - old
	for {
		// 实现乐观锁　igid　必须存在　调用该方法前已经校验
		g, err := r.GetGroup(ctx, igid)
		if err != nil {
			return err
		}
		avg := 0.0
		for _, t := range g.GroupTotal {
			if t.ITCode == code {
				avg = float64(t.TotalScore+c) / float64(t.Total)
				break
			}
		}

		query := bson.M{
			"_id":           igid,
			"totals.itCode": code,
		}
		update := bson.M{
			"$inc": bson.M{
				"totals.$.totalScore": c,
			},
			"$set": bson.M{"totals.$.avgScore": avg},
		}
		// 修改统计信息
		if err := r.DBUpdate(ctx, collNameGroup, query, update, true); err != mgo.ErrNotFound {
			if err != nil {
				return errors.Wrapf(err, "更新互动组互动统计失败．")
			}
			return nil
		}
		//　找不到　　"totals.itCode"　新增
		log.Debug("触发乐观锁 修改")
		query = bson.M{
			"_id":    igid,
			"totals": bson.M{"$not": bson.M{"$elemMatch": bson.M{"itCode": code}}},
		}
		update = bson.M{
			"$addToSet": bson.M{"totals": bson.M{"itCode": code, "total": 1, "totalScore": new, "avgScore": new}},
		}
		if err := r.DBUpdate(ctx, collNameGroup, query, update, true); err != mgo.ErrNotFound {
			if err != nil {
				return errors.Wrapf(err, "修改互动组互动统计失败．")
			}
			return nil
		}
		log.Debug("触发乐观锁　下一次更新")
		// 新增时出现 mgo.ErrNotFound 已经新增重新回到开始进行更新
	}
}
func (r groupRepo) UpdateGroupCtrl(ctx ddd.Context, igid string, ctrl cinteractiond.GroupCtrl) (err error) {
	update := bson.M{
		"isReplay":    ctrl.IsReplay,
		"isReplayChk": ctrl.IsReplayChk,
		"allowCodes":  ctrl.AllowCodes,
	}
	return r.DBUpdateCollAggregate(ctx, &collGroup{GroupID: igid}, update)
}
